#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "mp4enc.h"
#include "mp4file.h"


//FIXME support 64 bit variant with wide placeholders
static int64_t updateSize(FILE *pb, int64_t pos)
{
	int64_t curpos = mp4_ftell(pb);
	mp4_fseek(pb, pos, SEEK_SET);
	put_be32(pb, curpos - pos); /* rewrite size */
	mp4_fseek(pb, curpos, SEEK_SET);
	return curpos - pos;
}

//获取H.264的avcc参数
static int ff_isom_write_avcc(FILE *pfile, Mp4Context *mov)
{
	if(mov->sps!=NULL&&mov->pps!=NULL){
		put_buffer(pfile,"\x01\x4D\x40\x14\xFF\xE1",6);
		put_be16(pfile,mov->sps_len);
		put_buffer(pfile,mov->sps,mov->sps_len);
		put_byte(pfile,01);
		put_be16(pfile,4);//mov->pps_len);
		put_buffer(pfile,mov->pps,mov->pps_len);
		return 0;
	}else{
		return -1;
	}
}

static int mov_write_tkhd_tag(FILE *pb, Mp4Context *mov)
{
	int64_t duration = MOV_TIMESCALE;
	int version = 0;
	(version == 1) ? put_be32(pb, 104) : put_be32(pb, 92); /* size */
	put_tag(pb, "tkhd");
	put_byte(pb, version);
	put_be24(pb, 0xf); /* flags (track enabled) */
	if (version == 1) {
		put_be64(pb, mov->time);
		put_be64(pb, mov->time);
	} else {
		put_be32(pb, mov->time);/* creation time */
		put_be32(pb, mov->time);/* modification time */
	}
	put_be32(pb, 1);/* track-id */
	put_be32(pb, 0); /* reserved */
	
	//这个值对播放器很重要, 具体时间还和mvhd的timescale相关,用来指定了时长
	(version == 1) ? put_be64(pb, mov->video_track_size*mov->MEDIA_SAMPLE_DURATION/MOV_TIMESCALE_TO_MEDIA_TIMESCALE): \
		put_be32(pb, mov->video_track_size*mov->MEDIA_SAMPLE_DURATION/MOV_TIMESCALE_TO_MEDIA_TIMESCALE);

	put_be32(pb, 0); /* reserved */
	put_be32(pb, 0); /* reserved */
	put_be32(pb, 0x0); /* reserved (Layer & Alternate group) */
	/* Volume, only for audio */
	// if(track->enc->codec_type == AVMEDIA_TYPE_AUDIO)				//注意以后的音视频流程差异，目前为视频
	// put_be16(pb, 0x0100);
	// else
	put_be16(pb, 0);
	put_be16(pb, 0); /* reserved */

	/* Matrix structure */
	put_be32(pb, 0x00010000); /* reserved */
	put_be32(pb, 0x0); /* reserved */
	put_be32(pb, 0x0); /* reserved */
	put_be32(pb, 0x0); /* reserved */
	put_be32(pb, 0x00010000); /* reserved */
	put_be32(pb, 0x0); /* reserved */
	put_be32(pb, 0x0); /* reserved */
	put_be32(pb, 0x0); /* reserved */
	put_be32(pb, 0x40000000); /* reserved */

	/* Track width and height, for visual only */
	// if(st && (track->enc->codec_type == AVMEDIA_TYPE_VIDEO ||
	// track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
	// double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio);
	// if(!sample_aspect_ratio || track->height != track->enc->height)
	// sample_aspect_ratio = 1;
	put_be32(pb, mov->width/*sample_aspect_ratio * track->enc->width*0x10000*/);
	put_be32(pb, mov->height/*track->height*0x10000*/);
	return 0x5c;
}


static int mov_write_mdhd_tag(FILE *pb,Mp4Context *mov)
{
	int version=0;
	(version == 1) ? put_be32(pb, 44) : put_be32(pb, 32); /* size */
	put_tag(pb, "mdhd");
	put_byte(pb, version);
	put_be24(pb, 0); /* flags */
	if (version == 1) {
		put_be64(pb, mov->time);//track->time);
		put_be64(pb, mov->time);//track->time);
	} else {
		put_be32(pb, mov->time);//track->time); /* creation time */
		put_be32(pb, mov->time);//track->time); /* modification time */
	}
	put_be32(pb, MEDIA_TIMESCALE2);//track->timescale); /* time scale (sample rate for audio) */
	(version == 1) ? put_be64(pb, mov->MEDIA_SAMPLE_DURATION*mov->video_track_size):\
		put_be32(pb, mov->MEDIA_SAMPLE_DURATION*mov->video_track_size); /* duration */
	put_be16(pb, H264_LANGUAGE);//track->language); /* language */
	put_be16(pb, 0); /* reserved (quality) */

	return 32;
}


static int mov_write_hdlr_tag(FILE *pb, Mp4Context *mov)
{
	const char *hdlr, *descr = NULL, *hdlr_type = NULL;
	int64_t pos = mp4_ftell(pb);

	// if (!mov) { /* no media --> data handler */
	// hdlr = "dhlr";
	// hdlr_type = "url ";
	// descr = "DataHandler";
	// } else {
	//hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0";
	hdlr= "\0\0\0\0";
	// if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) {
	hdlr_type = "vide";
	descr = "huangwm999@gmail.com\0";

	put_be32(pb, 0); /* size */
	put_tag(pb, "hdlr");
	put_be32(pb, 0); /* Version & flags */
	put_buffer(pb, hdlr, 4); /* handler */
	put_tag(pb, hdlr_type); /* handler type */
	put_be32(pb ,0); /* reserved */
	put_be32(pb ,0); /* reserved */
	put_be32(pb ,0); /* reserved */
	// if (!track || track->mode == MODE_MOV)
	// put_byte(pb, strlen(descr)); /* pascal string */
	put_buffer(pb, descr, strlen(descr)); /* handler description */
	put_byte(pb, 0);						//输出字符结束符\0
	// if (track && track->mode != MODE_MOV)
	// put_byte(pb, 0); /* c string */
	return updateSize(pb, pos);
}


static int mov_write_vmhd_tag(FILE *pb)
{
	put_be32(pb, 0x14); /* size (always 0x14) */
	put_tag(pb, "vmhd");
	put_be32(pb, 0x01); /* version & flags */
	put_be64(pb, 0); /* reserved (graphics mode = copy) */
	return 0x14;
}


static int mov_write_dref_tag(FILE *pb)
{
	put_be32(pb, 28); /* size */
	put_tag(pb, "dref");
	put_be32(pb, 0); /* version & flags */
	put_be32(pb, 1); /* entry count */

	put_be32(pb, 0xc); /* size */
	put_tag(pb, "url ");
	put_be32(pb, 1); /* version & flags */

	return 28;
}

static int mov_write_dinf_tag(FILE *pb)
{
	int64_t pos = mp4_ftell(pb);
	put_be32(pb, 0); /* size */
	put_tag(pb, "dinf");
	mov_write_dref_tag(pb);
	return updateSize(pb, pos);
}


/* Time to sample atom */
static int mov_write_stts_tag(FILE *pb,Mp4Context *mov)
{
	// MOVStts *stts_entries;
	uint32_t entries = -1;
	uint32_t atom_size;
	uint32_t i;

	entries=1;//mov->video_track_size;
	atom_size = 16 + (entries * 8);
	put_be32(pb, atom_size); /* size */
	put_tag(pb, "stts");
	put_be32(pb, 0); /* version & flags */
	put_be32(pb, entries); /* entry count *///这个实例中记录所有sample的duration
	for (i=0; i<entries; i++) {
		put_be32(pb, mov->video_track_size);//H264_TRACK_ENTITY);//stts_entries[i].count);
		put_be32(pb, mov->MEDIA_SAMPLE_DURATION);//stts_entries[i].duration);
	}
	// av_free(stts_entries);
	return atom_size;
}


/* Sync sample atom */
static int mov_write_stss_tag(FILE *pb, Mp4Context *mov)//*nal_list *track*/, uint32_t flag)
{
	int64_t curpos, entryPos;
	int i, index = 0;
	int64_t pos = mp4_ftell(pb);
	nal_list * head=mov->video_track;
	put_be32(pb, 0); // size
	//put_tag(pb, flag == MOV_SYNC_SAMPLE ? "stss" : "stps");
	put_tag(pb, "stss");
	put_be32(pb, 0); // version & flags
	entryPos = mp4_ftell(pb);
	//put_be32(pb, track->entry); // entry count
	put_be32(pb, 1); // entry count

	i=0;
	while(head!=NULL){
		if(head->nal_type==1){
			put_be32(pb, i+1);
			index++;
		}
		i++;
		head=head->next;
	}
	curpos = mp4_ftell(pb);
	mp4_fseek(pb, entryPos, SEEK_SET);
	put_be32(pb, index); // rewrite size
	mp4_fseek(pb, curpos, SEEK_SET);
	return updateSize(pb, pos);
}


/* Sample to chunk atom */
static int mov_write_stsc_tag(FILE *pb, Mp4Context *mov)
{
	int index = 0, oldval = -1;
	int64_t entryPos, curpos;

	int64_t pos = mp4_ftell(pb);
	put_be32(pb, 0); /* size */
	put_tag(pb, "stsc");
	put_be32(pb, 0); // version & flags
	entryPos = mp4_ftell(pb);
	put_be32(pb, mov->video_track_size);//track->entry); // entry count
	//for (i=0; i<H264_TRACK_ENTITY; i++) {
	//if(oldval != track->cluster[i].samplesInChunk)
	//{
	put_be32(pb, 1); // first chunk
	put_be32(pb, 1);//track->cluster[i].samplesInChunk); // samples per chunk
	put_be32(pb, 0x1); // sample description index
	// oldval = track->cluster[i].samplesInChunk;
	// index++;
	//}
	//}
	index=1;
	curpos = mp4_ftell(pb);
	mp4_fseek(pb, entryPos, SEEK_SET);
	put_be32(pb, index); // rewrite size
	mp4_fseek(pb, curpos, SEEK_SET);
	return updateSize(pb, pos);
}


/* Sample size atom */
static int mov_write_stsz_tag(FILE *pb, Mp4Context *mov)
{
	int equalChunks = 1;
	uint32_t i;
	//int j, entries = 0, tst = -1, oldtst = -1;
	nal_list * track=mov->video_track;
	int64_t pos = mp4_ftell(pb);
	put_be32(pb, 0); /* size */
	put_tag(pb, "stsz");
	put_be32(pb, 0); /* version & flags */
	put_be32(pb, 0); // sample size
	put_be32(pb, mov->video_track_size); // sample count

	for (i=0; i<mov->video_track_size; i++){
		//if(one_node->nal_type!=2&&one_node->nal_type!=3){
		put_be32(pb,track->nal_size);
		track=track->next;
		//}
	}
	return updateSize(pb, pos);
}


/* Chunk offset atom */
static int mov_write_stco_tag(FILE *pb, Mp4Context *mov)
{
	uint32_t i;
	int mode64 = 0; // use 32 bit size variant if possible
	uint32_t offset_begin=mov->mdat_pos+8;	//获取mdat起始文件偏移
	int64_t pos = mp4_ftell(pb);
	nal_list * track=mov->video_track;
	put_be32(pb, 0); /* size */
	if (pos > UINT32_MAX) {
		mode64 = 1;
		put_tag(pb, "co64");
	} else
		put_tag(pb, "stco");
	put_be32(pb, 0); /* version & flags */
	put_be32(pb, mov->video_track_size); /* entry count */
	for (i=0; i<mov->video_track_size; i++) {
		if(mode64 == 1)
			put_be64(pb, offset_begin+track->nal_offset);//文件偏移地址
		else
			put_be32(pb, offset_begin+track->nal_offset);
		track=track->next;
	}
	return updateSize(pb, pos);
}


static int mov_write_avcc_tag(FILE *pb, Mp4Context *mov)
{
	int64_t pos = mp4_ftell(pb);	
	put_be32(pb, 0);
	put_tag(pb, "avcC");
	ff_isom_write_avcc(pb, mov);
	return updateSize(pb, pos);
}

static int mov_write_video_tag(FILE *pb, Mp4Context *mov)
{
	int64_t pos = mp4_ftell(pb);
	char compressor_name[32];

	put_be32(pb, 0); /* size */
	//put_le32(pb, H264_TRACK_TAG);// store it byteswapped
	put_tag(pb,"avc1");
	put_be32(pb, 0); /* Reserved */
	put_be16(pb, 0); /* Reserved */ 
	put_be16(pb, 1); /* Data-reference index */

	put_be16(pb, 0); /* Codec stream version */
	put_be16(pb, 0); /* Codec stream revision (=0) */
	// if (track->mode == MODE_MOV) {
	// put_tag(pb, "FFMP"); /* Vendor */
	// if(track->enc->codec_id == CODEC_ID_RAWVIDEO) {
	// put_be32(pb, 0); /* Temporal Quality */
	// put_be32(pb, 0x400); /* Spatial Quality = lossless*/
	// } else {
	// put_be32(pb, 0x200); /* Temporal Quality = normal */
	// put_be32(pb, 0x200); /* Spatial Quality = normal */
	// }
	// } else {
	put_be32(pb, 0); /* Reserved */
	put_be32(pb, 0); /* Reserved */
	put_be32(pb, 0); /* Reserved */
	// }
	put_be16(pb, mov->width/*track->enc->width*/); /* Video width */
	put_be16(pb, mov->height/*track->height*/); /* Video height */
	put_be32(pb, 0x00480000); /* Horizontal resolution 72dpi */
	put_be32(pb, 0x00480000); /* Vertical resolution 72dpi */
	put_be32(pb, 0); /* Data size (= 0) */
	put_be16(pb, 1); /* Frame count (= 1) */

	memset(compressor_name,0,32);
	/* FIXME not sure, ISO 14496-1 draft where it shall be set to 0 */
	// if (track->mode == MODE_MOV && track->enc->codec && track->enc->codec->name)
	// strncpy(compressor_name,track->enc->codec->name,31);//有问题
	put_byte(pb, strlen(compressor_name));
	put_buffer(pb, compressor_name, 31);

	// if (track->mode == MODE_MOV && track->enc->bits_per_coded_sample)
	// put_be16(pb, track->enc->bits_per_coded_sample);
	// else
	put_be16(pb, 0x18); /* Reserved */
	put_be16(pb, 0xffff); /* Reserved */
	// if(track->tag == MKTAG('m','p','4','v'))
	// mov_write_esds_tag(pb, mov);
	// else if(track->enc->codec_id == CODEC_ID_H263)
	// mov_write_d263_tag(pb);
	// else if(track->enc->codec_id == CODEC_ID_SVQ3)
	// mov_write_svq3_tag(pb);
	// else if(track->enc->codec_id == CODEC_ID_DNXHD)
	// mov_write_avid_tag(pb, mov);
	// else if(track->enc->codec_id == CODEC_ID_H264) {
	mov_write_avcc_tag(pb, mov);
	// if(track->mode == MODE_IPOD)
	// mov_write_uuid_tag_ipod(pb);
	// } else if(track->vosLen > 0)
	// mov_write_glbl_tag(pb, mov);
	return updateSize(pb, pos);
}


static int mov_write_stsd_tag(FILE *pb, Mp4Context *mov)
{
	int64_t pos = mp4_ftell(pb);
	put_be32(pb, 0); /* size */
	put_tag(pb, "stsd");
	put_be32(pb, 0); /* version & flags */
	put_be32(pb, 1); /* entry count */
	// if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO)			//目前仅做视频
	mov_write_video_tag(pb, mov);
	// else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO)
	// mov_write_audio_tag(pb, mov);
	return updateSize(pb, pos);
}

static int mov_write_stbl_tag(FILE *pb, Mp4Context *mov)
{
	int64_t pos = mp4_ftell(pb);
	put_be32(pb, 0); /* size */
	put_tag(pb, "stbl");
	mov_write_stsd_tag(pb, mov);
	mov_write_stts_tag(pb, mov);
	mov_write_stss_tag(pb, mov);
	mov_write_stsc_tag(pb, mov);
	mov_write_stsz_tag(pb, mov);
	mov_write_stco_tag(pb, mov);
	return updateSize(pb, pos);
}

static int mov_write_minf_tag(FILE *pb, Mp4Context *mov)
{
	int64_t pos = mp4_ftell(pb);
	put_be32(pb, 0); /* size */
	put_tag(pb, "minf");
	/* if(track->enc->codec_type == AVMEDIA_TYPE_VIDEO)*/
	mov_write_vmhd_tag(pb);
	mov_write_dinf_tag(pb);
	mov_write_stbl_tag(pb, mov);
	return updateSize(pb, pos);
}

static int mov_write_mdia_tag(FILE *pb, Mp4Context *mov)
{
	int64_t pos = mp4_ftell(pb);
	put_be32(pb, 0); /* size */
	put_tag(pb, "mdia");
	mov_write_mdhd_tag(pb, mov);
	mov_write_hdlr_tag(pb, mov);
	mov_write_minf_tag(pb, mov);
	return updateSize(pb, pos);
}


// This box seems important for the psp playback ... without it the movie seems to hang
static int mov_write_edts_tag(FILE *pb, Mp4Context *mov)
{
	put_be32(pb, 0x24); /* size */
	put_tag(pb, "edts");
	put_be32(pb, 0x1c); /* size */
	put_tag(pb, "elst");
	put_be32(pb, 0x0);
	put_be32(pb, 0x1);
	/* duration ... doesn't seem to effect psp */
	put_be32(pb,mov->MEDIA_SAMPLE_DURATION*mov->video_track_size);
	//put_be32(pb, track->cluster[0].cts); /* first pts is cts since dts is 0 */
	put_be32(pb,0);
	put_be32(pb, 0x00010000);
	return 0x24;
}


static int mov_write_trak_tag(FILE *pb, Mp4Context *mov)
{
	int64_t pos = mp4_ftell(pb);
	put_be32(pb, 0); /* size */
	put_tag(pb, "trak");
	mov_write_tkhd_tag(pb, mov);
	// if (track->mode == MODE_PSP || track->flags & MOV_TRACK_CTTS)
	mov_write_edts_tag(pb, mov); // PSP Movies require edts box
	// if (track->tref_tag)
	// mov_write_tref_tag(pb, mov);
	mov_write_mdia_tag(pb, mov);
	return updateSize(pb, pos);
}


static int mov_write_mvhd_tag(FILE *pb, Mp4Context *mov)
{
	int maxTrackID = 1;
	int64_t maxTrackDuration = 0;
	int version;
	//视频的总时间=一个track的总时间
	maxTrackDuration=mov->video_track_size*mov->MEDIA_SAMPLE_DURATION/MOV_TIMESCALE_TO_MEDIA_TIMESCALE;
	//version = maxTrackDuration < UINT32_MAX ? 0 : 1;
	version = 0;						//定义为不超过4G的Mp4
	(version == 1) ? put_be32(pb, 120) : put_be32(pb, 108); /* size */
	put_tag(pb, "mvhd");
	put_byte(pb, version);
	put_be24(pb, 0); /* flags */
	if (version == 1) {
		put_be64(pb, mov->time);
		put_be64(pb, mov->time);
	} else {
		put_be32(pb, mov->time); /* creation time */	//时间的格式 HFS时间
		put_be32(pb, mov->time); /* modification time */
	}
	put_be32(pb, MOV_TIMESCALE);
	(version == 1) ? put_be64(pb, maxTrackDuration) : put_be32(pb, maxTrackDuration); /* duration of longest track */

	put_be32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
	put_be16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
	put_be16(pb, 0); /* reserved */
	put_be32(pb, 0); /* reserved */
	put_be32(pb, 0); /* reserved */

	/* Matrix structure */
	put_be32(pb, 0x00010000); /* reserved */
	put_be32(pb, 0x0); /* reserved */
	put_be32(pb, 0x0); /* reserved */
	put_be32(pb, 0x0); /* reserved */
	put_be32(pb, 0x00010000); /* reserved */
	put_be32(pb, 0x0); /* reserved */
	put_be32(pb, 0x0); /* reserved */
	put_be32(pb, 0x0); /* reserved */
	put_be32(pb, 0x40000000); /* reserved */

	put_be32(pb, 0); /* reserved (preview time) */
	put_be32(pb, 0); /* reserved (preview duration) */
	put_be32(pb, 0); /* reserved (poster time) */
	put_be32(pb, 0); /* reserved (selection time) */
	put_be32(pb, 0); /* reserved (selection duration) */
	put_be32(pb, 0); /* reserved (current time) */
	put_be32(pb, maxTrackID+1); /* Next track id */
	return 0x6c;
}


static int mov_write_moov_tag(FILE *pb, Mp4Context *mov)
{
	int64_t pos = mp4_ftell(pb);
	put_be32(pb, 0); /* size placeholder*/
	put_tag(pb, "moov");

	mov_write_mvhd_tag(pb, mov);
	mov_write_trak_tag(pb, mov);
	return updateSize(pb, pos);
}

static int mov_write_trailer(FILE *pb,Mp4Context *mov)
{
	int res = 0;
	int64_t moov_pos = mp4_ftell(pb);
	/* Write size of mdat tag */
	if (mov->mdat_size+8 <= UINT32_MAX) {
		mp4_fseek(pb, mov->mdat_pos, SEEK_SET);
		put_be32(pb, mov->mdat_size+8);
	} else {
		/* overwrite 'wide' placeholder atom */
		mp4_fseek(pb, mov->mdat_pos - 8, SEEK_SET);
		put_be32(pb, 1); /* special value: real atom size will be 64 bit value after tag field */
		put_tag(pb, "mdat");
		put_be64(pb, mov->mdat_size+16);
	}
	mp4_fseek(pb, moov_pos, SEEK_SET);
	//--------------------------------------
	//以上写入mdat成功
	//--------------------------------------
	mov_write_moov_tag(pb, mov);
	return res;
}

/* TODO: This needs to be more general */
static int mov_write_ftyp_tag(FILE *pb, Mp4Context * mov)
{
	int64_t pos = mp4_ftell(pb);
	put_be32(pb, 0); /* size */
	put_tag(pb, "ftyp");
	put_tag(pb,"3gp6");
	put_be32(pb, 0x00000100);
	put_tag(pb,"3gp6");
	put_tag(pb, "3gp5");
	put_tag(pb, "3gp4");
	put_tag(pb, "avc1");
	return updateSize(pb, pos);
}


static int mov_write_mdat_tag(FILE *pb, Mp4Context *mov)
{
	put_be32(pb, 8); // placeholder for extended size field (64 bit)
	put_tag(pb, "wide");//mov->mode == MODE_MOV ? "wide" : "free");	
	mov->mdat_pos = mp4_ftell(pb);
	put_be32(pb, 0); /* size placeholder*/
	put_tag(pb, "mdat");
	return 0;
}

static int mov_write_header(FILE *pb,Mp4Context * mov)
{
	int hint_track = 0;
	mov_write_ftyp_tag(pb,mov);
	mov_write_mdat_tag(pb, mov);
	return 0;
}

//-------------------------轻量级nal_list-----------------------------
void nal_list_insert_end( nal_list* new_node,Mp4Context *mov )
{
	new_node->next=NULL;
	mov->video_track_size++;
	if(mov->video_track==NULL){										//处理第一个帧的问题
		mov->video_track=new_node;
	}else{
		mov->tail->next=new_node;
	}
	mov->tail=new_node;
	return;
}

uint32_t nal_list_get_size(Mp4Context *mov){
	return mov->video_track_size;
}

nal_list * nal_list_get_head(Mp4Context *mov){
	return mov->video_track;
}

void nal_list_free(Mp4Context *mov)
{
	while(mov->video_track!=NULL){
		nal_list * p1=mov->video_track;
		mov->video_track=mov->video_track->next;
		free(p1);
	}
	mov->video_track=mov->tail=NULL;							//清空头与尾
	return;
}



 
 //-------------------------主函数测试-----------------------------
 #if 1
 #define BUFSIZE (1024 * 1024)
 unsigned char buffer[BUFSIZE];
 int m_nPos = 0;
 int m_nPrepos = 0;
 int g_nSize = 0;
 int InitFirstPos(unsigned char* pData, unsigned int uiSize)
 {
 while(m_nPos < uiSize - 4)
 {
 if(pData[m_nPos] == 0x00)
 if(pData[m_nPos+1] == 0x00)
 if(pData[m_nPos+2] == 0x00)
 if(pData[m_nPos+3] == 0x01)
 break;
 m_nPos ++;
 }
 
 m_nPrepos = m_nPos;
 return 0;
 }
 int open_h264(const char* fileName)
 {
 FILE *fp = 0;
 int size;
 
 fp = fopen(fileName, "rb");
 if(fp == 0)
 {
 printf("Failed to open %s\n", fileName);
 return -1;
 }
 fseek(fp, 0, SEEK_SET);
 size = fread(buffer, sizeof(unsigned char), BUFSIZE, fp);
 if(size >= BUFSIZE)
 {
 printf("File size is larger than BUFSIZE\n");
 }
 else printf("File size is smaller than BUFSIZE\n");
 
 g_nSize = size;
 
 if(!fp)
 fclose(fp);
 
 InitFirstPos(buffer, g_nSize);
 return 0;
 }
 
 uint8_t* read_nal_from_h264(uint64_t* pSize)
 {
 uint8_t* pData = NULL;
 m_nPos = m_nPrepos + 4;
 while(m_nPos < g_nSize - 4)
 {
 if(buffer[m_nPos] == 0x00)
 if(buffer[m_nPos+1] == 0x00)
 if(buffer[m_nPos+2] == 0x00)
 if(buffer[m_nPos+3] == 0x01)
 break;
 m_nPos ++;
 }
 if(m_nPos == g_nSize - 4)
 {
 return NULL;
 }
 
 *pSize = m_nPos - (m_nPrepos/*+4*/);
pData = (uint8_t*)malloc(*pSize);
memset(pData, 0, *pSize);
memcpy(pData, buffer+(m_nPrepos/*+4*/), *pSize);
m_nPrepos = m_nPos;
return pData;
}

int close_h264()
{
    return 0;
}

//FIXME: - 需要修改文件路径
int main(){
    Mp4Context * mov=malloc(sizeof(Mp4Context));
    FILE * fp=mp4_fopen("/Users/imac/Desktop/11/result1.mp4","wb");
    int nal_list_len=0;
    int nal_list_it=0;
    nal_list * nal_list_head=NULL;
    uint64_t size=0;
    uint64_t sum_size=0;
    uint8_t * buf=NULL;
    nal_list *one_node=NULL;
    //uint32_t max_nal=6;
    memset(mov,0,sizeof(Mp4Context));
    mov->MEDIA_SAMPLE_DURATION=MEDIA_TIMESCALE2/25;
    
    mov->mp4_fp=fp;
    mov->time=0xC6BFDE31;
    mov_write_header(mov->mp4_fp,mov);//写了Mp4的头部与mdat的头部
    
//    open_h264("TEST-Huawei.264");
    open_h264("/Users/imac/Desktop/11/TEST-Huawei.264");
    
    while((buf=read_nal_from_h264(&size))!=NULL)
    {
        int nal_type=0;
        int buf_it=0;
        int type = 0;
        //printf("offset:%d\tsize:%x\n",sum_size,size);
        //------------------保存分析结果------------------------------
        if(size<5){                            //无法进行类型判断故不做分析
            free(buf);
            continue;
        }
        
        type = buf[4]&0x1F;
        switch (type)
        {
            case 7:                            //SPS信息
                nal_type=2;
                if(0==mov->sps_len){        //记录一次SPS
                    mov->sps_len=size-4;
                    mov->sps=malloc(mov->sps_len);
                    memcpy(mov->sps,buf+4,mov->sps_len);
                }
                
                break;
            case 8:                            //PPS信息
                nal_type=3;
                if(0==mov->pps_len){        //记录一次PPS
                    mov->pps_len=size-4;
                    mov->pps=malloc(mov->pps_len);
                    memcpy(mov->pps,buf+4,mov->pps_len);
                }
                break;
            case 5:                            //IDR帧信息
                nal_type=1;
                break;
            case 6:                            //SEI信息
                nal_type=4;
                break;
            case 1:                            //B,P帧默认为0
                nal_type=0;
                break;
            default:                        //未识别帧
                nal_type=-1;
                break;
        }
        one_node=(nal_list *)malloc(sizeof(struct nal_list));
        one_node->nal_type=nal_type;
        one_node->nal_offset=sum_size;
        one_node->nal_size=size;
        one_node->next=NULL;
        
        //one_node->nal_type!=2&&one_node->nal_type!=3&&one_node->nal_type!=4){
        if(one_node->nal_type==1||one_node->nal_type==0){
            nal_list_insert_end(one_node,mov);
            put_h264_buffer(mov->mp4_fp,buf,size);        //把数据输入mp4文件
            sum_size+=size;
        }
        //------------------------------------------------------------
        free(buf);
        buf=NULL;
    }
    close_h264();
    mov->mdat_size=sum_size;
    mov->video_track=nal_list_get_head(mov);
    //    mov->video_track_size=nal_list_get_size(mov);    //可不更新
    mov->width= 252;                                //测试264文件宽度
    mov->height= 288;                        //测试264文件高度
    
    printf("sum_nal:%d\n",mov->video_track_size);    //输出总长度
    printf("sum_size:0x%x\n",sum_size);                //输出总长度
    
    mov_write_trailer(mov->mp4_fp,mov);
    mp4_fclose(mov->mp4_fp);
    free(mov);
    return 0;
}
#endif /*main*/
 
 











//从输入pBuf分离出Nal数据 lNalTypeOffset用于兼容00 00 00 00 00....01 09[lNalTypeOffset]
static uint8_t * bufferToNal(uint8_t* pBuf,uint64_t lBufLen,uint64_t * lOffset,uint64_t * lNalSize,uint64_t *lNalTypeOffset){
//	if(*lOffset>=lBufLen){
//		return NULL;
//	}
	uint8_t state=0;									//定义自动机监测的初始状态
	uint64_t nal_begin=0;
	uint64_t nal_end=0;
	uint8_t ch=0;
	while(*lOffset<lBufLen&&state!=3) 
	{
		ch=pBuf[*lOffset];
		switch(state)
		{
		case 0:
			if(ch=='\x00'){
				state=1;
				nal_begin=*lOffset;						//偏移到00的那个位置
			}else{
				state=0;
			}
			break;
		case 1:
			if(ch=='\x00'){
				state=2;
			}else{
				state=0;
			}
			break;
		case 2:
			if(ch=='\x00'){
				state=2;
			}else if(ch=='\x01'){
				state=3;
			}else{
				state=0;
			}
			break;
		}
		*lOffset=*lOffset+1;							//读取下一个字节
	}
	if(3==state){										//监测到下一个Nal单元,并记录了起始位置
		*lNalTypeOffset=*lOffset-nal_begin;				//当前Nal码所在位置对于的相对位置
		state=0;										//重新初始化为0状态
		while(*lOffset<lBufLen&&state!=3)				//监测直至文件结束
		{
			ch=pBuf[*lOffset];
			switch(state)
			{
			case 0:
				if(ch=='\x00'){
					state=1;
					nal_end=*lOffset;					//偏移到00的那个位置
				}else{
					state=0;
				}
				break;
			case 1:
				if(ch=='\x00'){
					state=2;
				}else{
					state=0;
				}
				break;
			case 2:
				if(ch=='\x00'){
					state=2;
				}else if(ch=='\x01'){
					state=3;
				}else{
					state=0;
				}
				break;
			}
			*lOffset=*lOffset+1;						//读取下一个字节
		}
		if(3==state){									//存在下一个Nall
			*lOffset=nal_end;							//偏移到00的那个位置
			*lNalSize=nal_end-nal_begin;
			return pBuf+nal_begin;
		}else{											//缓存结尾
			*lNalSize=*lOffset-nal_begin;				
			return pBuf+nal_begin;
		}
	}else{												//未发现nal单元，返回为空，lOffset为0
		*lNalSize=0;
		*lNalTypeOffset=-1;
		return NULL;
	}
}

//---------------------------------多路接口实现-----------------------------------------
int isInstancesInit=0;
Mp4Context * mp4ContextSet=NULL;
LONG GetInstance(){
	int instance_it=0;
	if(0==isInstancesInit){									//INSTANCE_ERROR表示错误码
		//printf("Memory:%d\n",sizeof(Mp4Context)*MAX_INSTANCE_NUM);
		mp4ContextSet=malloc(sizeof(Mp4Context)*MAX_INSTANCE_NUM);
		if(NULL==mp4ContextSet){
			return INSTANCE_ERROR;
		}													//内部结构未初始化
		memset(mp4ContextSet,0,sizeof(Mp4Context)*MAX_INSTANCE_NUM);	//清空数据
		isInstancesInit=1;
	}														//当前数据结构为mov[SumOfInstance-1] rang:0~31
	for(instance_it=0;instance_it<MAX_INSTANCE_NUM;instance_it++){
		if(mp4ContextSet[instance_it].isUsed>0){
			continue;
		}else{
			memset(mp4ContextSet+instance_it,0,sizeof(Mp4Context));		//而清空内部数据放在GetInstance时做
			mp4ContextSet[instance_it].isUsed=1;
			mp4ContextSet[instance_it].MEDIA_SAMPLE_DURATION=MEDIA_TIMESCALE2/25;		//设置帧率的默认值
			return instance_it;								//返回lHandle:0~31
			break;
		}
	}
	return INSTANCE_ERROR;									//返回错误
}

LONG ReleaseInstance(LONG lHandle){
	Mp4Context *mov=mp4ContextSet+lHandle;
	if(mp4ContextSet[lHandle].isUsed==1){					
		mp4ContextSet[lHandle].isUsed=0;					//只有Stop后可以调用ReleaseInstance
	}else{
		return INSTANCE_ERROR;								
	}

	nal_list_free(mov);
	//memset(mov,0,sizeof(Mp4Context));						//清空数据
	//不做Memset,防止isUsed=0是正好分配相应路的解码任务
	//而清空内部数据放在GetInstance时做
	mov->isUsed=0;
	return INSTANCE_OK;										//返回成功
}

LONG SetVideoFrameRate(LONG lHandle, LONG lFrameRate){
	Mp4Context *mov=mp4ContextSet+lHandle;					//获取句柄数据
	if(0==lFrameRate){										//除零错误
		return INSTANCE_ERROR;								//返回失败
	}
	if(mp4ContextSet[lHandle].isUsed==0){					//只有非状态0的可以调用SetVideoFrameRate
		return INSTANCE_ERROR;
	}else{
		mp4ContextSet[lHandle].MEDIA_SAMPLE_DURATION=MEDIA_TIMESCALE2/lFrameRate;								
	}
	return INSTANCE_OK;										//返回成功
}

LONG StartWrite(LONG lHandle, CHAR* pszFileName){
	Mp4Context *mov=mp4ContextSet+lHandle;					//获取句柄数据
	FILE * fp=NULL;
	if(mp4ContextSet[lHandle].isUsed==1){					//只有初始化的可以调用StartWrite
		mp4ContextSet[lHandle].isUsed=2;
	}else{
		return INSTANCE_ERROR;								
	}
	mov->time=0;
    mov->mdat_pos=0;
    mov->mdat_size=0;
	mov->sps=NULL;
	mov->sps_len=0;
	mov->pps=NULL;
	mov->pps_len=0;
	mov->video_track=NULL;							//记录帧的首部
	mov->tail=NULL;									//记录帧的尾部
	mov->video_track_size=0;
	mov->width=0;
	mov->height=0;

	fp=mp4_fopen(pszFileName,"wb");
	mov->mp4_fp=fp;
	mov->time=0xC6BFDE31;
	mov_write_header(mov->mp4_fp,mov);						//写了Mp4的头部与mdat的头部
	return INSTANCE_OK;										//返回成功
}

LONG InsertVideoBuffer(LONG lHandle ,VOID* pBuf,ULONG lBufLen){
	Mp4Context *mov=mp4ContextSet+lHandle;					//获取句柄数据
	uint8_t * bufAllNal=(uint8_t *)pBuf;							//类型转换
	nal_list *one_node=NULL;
	int nal_type=0;				
	int buf_it=0;
	
	//分离各组带起始码的Nal数据
	uint64_t lOffset=0;
	uint8_t *buf=NULL;
	uint64_t lNalSize=0;
	uint64_t lNalTypeOffset=-1;

	if(mp4ContextSet[lHandle].isUsed==2){					//只有Start后可以调用InsertVideoBuffer
		;
	}else{
		return INSTANCE_ERROR;								
	}
	
	while((buf=bufferToNal(bufAllNal,lBufLen,&lOffset,&lNalSize,&lNalTypeOffset))!=NULL){
		if(lOffset>lBufLen||lNalTypeOffset>=lNalSize){			//lOffset不可能大于lBufLen,且有一帧无法进行类型判断故不做分析
			return INSTANCE_ERROR;								//返回错误
		}
		switch (buf[lNalTypeOffset]&0x1F)
		{
		case 7:													//SPS信息
			nal_type=2;
			if(0==mov->sps_len){								//记录一次SPS
				mov->sps_len=lNalSize-lNalTypeOffset;		
				mov->sps=malloc(mov->sps_len);
				memcpy(mov->sps,buf+lNalTypeOffset,mov->sps_len);
			}
			break;
		case 8:													//PPS信息
			nal_type=3;
			if(0==mov->pps_len){								//记录一次PPS
				mov->pps_len=lNalSize-lNalTypeOffset;
				mov->pps=malloc(mov->pps_len);
				memcpy(mov->pps,buf+lNalTypeOffset,mov->pps_len);
			}
			break;
		case 5:													//IDR帧信息
			nal_type=1;
			break;
		case 6:													//SEI信息
			nal_type=4;
			break;
		case 1:													//B,P帧默认为0
			nal_type=0;
			break;
		default:												//未识别帧
			nal_type=-1;
			break;
		}
		one_node=(nal_list *)malloc(sizeof(struct nal_list));
		one_node->nal_type=nal_type;
		one_node->nal_offset=mov->mdat_size;
		one_node->nal_size=lNalSize;
		one_node->next=NULL;
		//one_node->nal_type!=2&&one_node->nal_type!=3&&one_node->nal_type!=4){
		if(one_node->nal_type==1||one_node->nal_type==0){
			if(lNalTypeOffset<4){
				continue;
			}
			nal_list_insert_end(one_node,mov);
			put_h264_buffer(mov->mp4_fp,buf+(lNalTypeOffset-4),lNalSize-(lNalTypeOffset-4));			//把数据输入mp4文件
			mov->mdat_size+=lNalSize-(lNalTypeOffset-4);
			continue;
		}else{
			free(one_node);
			one_node=NULL;
		}
	}
	return INSTANCE_OK;											//返回成功
}

LONG InsertAudioBuffer(LONG lHandle ,VOID* pBuf,ULONG lBufLen){
	return INSTANCE_OK;											//返回成功
}

LONG Stop(LONG lHandle){
	Mp4Context *mov=mp4ContextSet+lHandle;

	if(mp4ContextSet[lHandle].isUsed==2){					
		mp4ContextSet[lHandle].isUsed=1;					//只有Start的文件可以调用Stop
	}else{
		return INSTANCE_ERROR;								
	}

	//--------计算SPS获取分辨率--------
	//mov->width=0;//252;									//测试264文件宽度
	//mov->height=0;//288;									//测试264文件高度
	dec_resolution(mov->sps,mov->sps_len,&(mov->width),&(mov->height));
	mov_write_trailer(mov->mp4_fp,mov);
	nal_list_free(mov);										//释放帧数据内存
	free(mov->pps);mov->pps=NULL;
	free(mov->sps);mov->sps=NULL;
	mp4_fclose(mov->mp4_fp);								//关闭文件
	mov->mp4_fp=NULL;
	return INSTANCE_OK;										//返回成功
}

LONG StartRead(LONG lHandle, CHAR* pszFileName){
	return INSTANCE_OK;										//返回成功
}


static char GetBitFromSPS(char *sps,int a,int length){
	if(((a>>3)+4)>=length){
		return 0;											//解析读取长度越界,返回0
	}else{
		return ((sps[(a>>3)+4]&(1<<(7-a%8)))!=0);
	}
}


//---------------------通过SPS获得分辨率--------------------
static uint32_t dec_resolution(uint8_t *sps,uint32_t length,uint32_t *width,uint32_t *height)
{ 
	uint32_t len=length,INFO=0,mb_width,mb_height,num_ref_frames_in_pic_order_cnt_cycle=0,\
		state=0,offset=0,i=0,a=0,count=0,count2=0,chongfu=0,chongfu2=0,chongfu3=0,\
		offset_for_ref_frame_count=0,k=0,xxx=0,chengfang=1;
	uint8_t *s=sps;
	s=s+3;
	if(len<=4){												//无法解析SPS,返回默认分辨率
		*width=0;
		*height=0;
		return 0;
	}
	for(count=0;count<2;count++) //seq_parameter_set_id,log2_max_frame_num_minus4
	{ 
		for(a=offset;a<(len-4)*8;a++)
		{
			if(GetBitFromSPS(sps,a,length)==1)
				break;
			else if(GetBitFromSPS(sps,a,length)==0)
				state++;
		}
		offset=offset+(2*state+1);
		state=0;
	}

	for(a=offset;a<(len-4)*8;a++) //pic_order_cnt_type
	{
		if(GetBitFromSPS(sps,a,length)==1)
			break;
		else if(GetBitFromSPS(sps,a,length)==0)
			state++; 
	}
	offset=offset+(2*state+1);
	///////////////////////////////////////////////////////
	// if( pic_order_cnt_type = = 0 ) //
	// log2_max_pic_order_cnt_lsb_minus4 // 
	///////////////////////////////////////////////////////
	if(state==0) { 
		for(a=offset;a<(len-4)*8;a++)
		{//offset=offset+(2*state+1);
			if(GetBitFromSPS(sps,a,length)==1)
				break;
			else if(GetBitFromSPS(sps,a,length)==0)
				state++; 
		}
		offset=offset+(2*state+1);
		state=0;
	}
	/////////////////////////////////////////////////////////////////////////////
	// else if( pic_order_cnt_type = = 1 ) { //
	// delta_pic_order_always_zero_flag 0 u(1) //
	// offset_for_non_ref_pic 0 se(v) //
	// offset_for_top_to_bottom_field 0 se(v) //
	// num_ref_frames_in_pic_order_cnt_cycle 0 ue(v) //
	// for( i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ ) //
	// offset_for_ref_frame[ i ] 0 se(v)} //
	/////////////////////////////////////////////////////////////////////////////

	else if(state==1)
	{ 
		offset++;
		for(count2=0;count2<2;count2++)
		{
			for(a=offset;a<(len-4)*8;a++)
			{
				if(GetBitFromSPS(sps,a,length)==1)
					break;
				else if(GetBitFromSPS(sps,a,length)==0)
					state++; 
			}
			offset=offset+(2*state+1);
			state=0;
		}

		for(a=offset;a<(len-4)*8;a++)
		{
			if(GetBitFromSPS(sps,a,length)==1)
				break;
			else if(GetBitFromSPS(sps,a,length)==0)
				state++; 
		}
		offset=offset+state+1;

		if(state==0) 
			num_ref_frames_in_pic_order_cnt_cycle=1;
		else{
			for(chongfu=0;chongfu<state;chongfu++){
				num_ref_frames_in_pic_order_cnt_cycle+=\
					GetBitFromSPS(sps,offset+state-1-chongfu,length)*(1<<chongfu);
			}
		}

		offset=offset+(2*state+1);

		state=0;

		for(offset_for_ref_frame_count=0;\
			offset_for_ref_frame_count<num_ref_frames_in_pic_order_cnt_cycle;\
			offset_for_ref_frame_count++) 
		{
			for(a=offset;a<(len-4)*8;a++)
			{
				if(GetBitFromSPS(sps,a,length)==1){
					break;
				}else if(GetBitFromSPS(sps,a,length)==0){
					state++; 
				}
			}
			offset=offset+(2*state+1);
			state=0;
		}
	}

	//////////////////////////////////////////////
	// num_ref_frames //
	//////////////////////////////////////////////
	for(a=offset;a<(len-4)*8;a++)
	{
		if(GetBitFromSPS(sps,a,length)==1){
			break;
		}else if(GetBitFromSPS(sps,a,length)==0){
			state++;
		}
	}
	offset=offset+(2*state+1);
	state=0;
	// offset=offset+3; 
	offset++; //gaps_in_frame_num_value_allowed_flag

	//////////////////开始分辨率参数提取///////////////////////////
	for(a=offset;a<(len-4)*8;a++)
	{
		if(GetBitFromSPS(sps,a,length)==1){
			break;
		}else if(GetBitFromSPS(sps,a,length)==0){
			state++; 
		}
	}
	offset=offset+(state+1);
	for(chongfu2=0;chongfu2<state;chongfu2++) 
	{ 
		for(k=0;k<chongfu2;k++){
			chengfang=chengfang*2;
		}
		INFO+=GetBitFromSPS(sps,offset+state-1-chongfu2,length)*chengfang;
		chengfang=1;
	}	
	for(k=0;k<state;k++){
		chengfang=chengfang*2;
	}
	mb_width=INFO+chengfang;
	chengfang=1;
	*width=mb_width*16;
	offset=offset+state;state=0;INFO=0;

	for(a=offset;a<(len-4)*8;a++)
	{
		if(GetBitFromSPS(sps,a,length)==1){
			break;
		}else if(GetBitFromSPS(sps,a,length)==0){
			state++; 
		}
	}
	offset=offset+(state+1);
	for(chongfu3=0;chongfu3<state;chongfu3++) 
	{ 
		for(k=0;k<chongfu3;k++)
		chengfang=chengfang*2;
		INFO+=GetBitFromSPS(sps,offset+state-1-chongfu3,length)*chengfang;
		chengfang=1;
	}
	for(k=0;k<state;k++){
		chengfang=chengfang*2;
	}
	mb_height=INFO+chengfang;
	chengfang=1;
	*height=mb_height*16;
	offset=offset+state;state=0;
	return 0;						//sps中分辨率之后的数据不再需要,不解析
}

